home *** CD-ROM | disk | FTP | other *** search
/ Aminet 7 / Aminet 7 - August 1995.iso / Aminet / comm / tcp / AmigaTCP.lha / AmigaTCP / src / tcpsubr.c < prev    next >
C/C++ Source or Header  |  1989-06-24  |  10KB  |  464 lines

  1. #ifdef    TRACE
  2. #include <stdio.h>
  3. #endif
  4.  
  5. #include "machdep.h"
  6. #include "timer.h"
  7. #include "mbuf.h"
  8. #include "netuser.h"
  9. #include "internet.h"
  10. #include "tcp.h"
  11.  
  12. struct tcb *tcbs[NTCB];
  13.  
  14. /* Lookup connection, return TCB pointer or NULLTCB if nonexistant */
  15. struct tcb *
  16. lookup_tcb(conn)
  17. struct connection *conn;
  18. {
  19.     register struct tcb *tcb;
  20.     int16 hash_tcb();    
  21.  
  22.     tcb = tcbs[hash_tcb(conn)];
  23.     while(tcb != NULLTCB){
  24.         /* Yet another structure compatibility hack */
  25.         if(conn->local.address == tcb->conn.local.address
  26.          && conn->remote.address == tcb->conn.remote.address
  27.          && conn->local.port == tcb->conn.local.port
  28.          && conn->remote.port == tcb->conn.remote.port)
  29.             break;
  30.         tcb = tcb->next;
  31.     }
  32.     return tcb;
  33. }
  34.  
  35. /* Create a TCB, return pointer. Return pointer if TCB already exists. */
  36. struct tcb *
  37. create_tcb(conn)
  38. struct connection *conn;
  39. {
  40.     char *calloc();
  41.     register struct tcb *tcb;
  42.     void tcp_timeout(),tcp_msl();
  43.     void link_tcb();
  44.  
  45.     if((tcb = lookup_tcb(conn)) != NULLTCB)
  46.         return tcb;
  47.     if((tcb = (struct tcb *)calloc(1,sizeof (struct tcb))) == NULLTCB)
  48.         return NULLTCB;
  49.     bcopy((char *)conn,(char *)&tcb->conn,sizeof(struct connection));
  50.  
  51.     tcb->mss = DEF_MSS;
  52.     tcb->srtt = DEF_RTT * MSPTICK;
  53.     /* Initialize retransmission timeout */
  54.     tcb->timer.start = (BETA * tcb->srtt)/MSPTICK;
  55.  
  56.     tcb->timer.func = tcp_timeout;
  57.     tcb->timer.arg = (int *)tcb;
  58.  
  59.     link_tcb(tcb);
  60.     return tcb;
  61. }
  62.  
  63. /* Close our TCB */
  64. void
  65. close_self(tcb,reason)
  66. register struct tcb *tcb;
  67. char reason;
  68. {
  69.     struct reseq *rp,*rp1;
  70.  
  71.     stop_timer(&tcb->timer);
  72.     tcb->reason = reason;
  73.  
  74.     /* Flush reassembly queue; nothing more can arrive */
  75.     for(rp = tcb->reseq;rp != NULLRESEQ;rp = rp1){
  76.         rp1 = rp->next;
  77.         free_p(rp->bp);
  78.         free((char *)rp);
  79.     }
  80.     tcb->reseq = NULLRESEQ;
  81.     setstate(tcb,CLOSED);
  82. }
  83.  
  84. /* Determine initial sequence number */
  85.  
  86. #ifdef    AMIGA
  87. /*
  88.  *  routine called at startup time with inital value of iss for system.  This
  89.  *  is probably based on the time or something
  90.  */
  91. static int32 seq;
  92.  
  93. void
  94. setiss(initval)
  95.     int32 initval;
  96. {
  97.     seq = initval;
  98. }
  99. #endif
  100.  
  101. int32
  102. iss()
  103. {
  104. #ifndef    AMIGA
  105.     static int32 seq;
  106. #endif
  107.     seq += 250000;
  108.     return seq;
  109. }
  110.  
  111. /* Sequence number comparisons
  112.  * Return true if x is between low and high inclusive,
  113.  * false otherwise
  114.  */
  115. int
  116. seq_within(x,low,high)
  117. register int32 x,low,high;
  118. {
  119.     if(low <= high){
  120.         if(low <= x && x <= high)
  121.             return 1;
  122.     } else {
  123.         if(low >= x && x >= high)
  124.             return 1;
  125.     }
  126.     return 0;
  127. }
  128. int
  129. seq_lt(x,y)
  130. register int32 x,y;
  131. {
  132.     return (long)(x-y) < 0;
  133. }
  134. int
  135. seq_le(x,y)
  136. register int32 x,y;
  137. {
  138.     return (long)(x-y) <= 0;
  139. }
  140. int
  141. seq_gt(x,y)
  142. register int32 x,y;
  143. {
  144.     return (long)(x-y) > 0;
  145. }
  146. int
  147. seq_ge(x,y)
  148. register int32 x,y;
  149. {
  150.     return (long)(x-y) >= 0;
  151. }
  152.  
  153. /* Hash a connect structure into the hash chain header array */
  154. static int16
  155. hash_tcb(conn)
  156. struct connection *conn;
  157. {
  158.     register int16 hval;
  159.  
  160.     /* Compute hash function on connection structure */
  161.     hval = hiword(conn->remote.address);
  162.     hval ^= loword(conn->remote.address);
  163.     hval ^= hiword(conn->local.address);
  164.     hval ^= loword(conn->local.address);
  165.     hval ^= conn->remote.port;
  166.     hval ^= conn->local.port;
  167.     hval %= NTCB;
  168.     return hval;
  169. }
  170. /* Insert TCB at head of proper hash chain */
  171. void
  172. link_tcb(tcb)
  173. register struct tcb *tcb;
  174. {
  175.     register struct tcb **tcbhead;
  176.     int16 hash_tcb();
  177.     char i_state;
  178.  
  179.     tcb->prev = NULLTCB;
  180.     i_state = disable();
  181.     tcbhead = &tcbs[hash_tcb(&tcb->conn)];
  182.     tcb->next = *tcbhead;
  183.     if(tcb->next != NULLTCB){
  184.         tcb->next->prev = tcb;
  185.     }
  186.     *tcbhead = tcb;
  187.     restore(i_state);
  188. }
  189. /* Remove TCB from whatever hash chain it may be on */
  190. void
  191. unlink_tcb(tcb)
  192. register struct tcb *tcb;
  193. {
  194.     register struct tcb **tcbhead;
  195.     int16 hash_tcb();
  196.     char i_state;
  197.  
  198.     i_state = disable();
  199.     tcbhead = &tcbs[hash_tcb(&tcb->conn)];
  200.     if(*tcbhead == tcb)
  201.         *tcbhead = tcb->next;    /* We're the first one on the chain */
  202.     if(tcb->prev != NULLTCB)
  203.         tcb->prev->next = tcb->next;
  204.     if(tcb->next != NULLTCB)
  205.         tcb->next->prev = tcb->prev;
  206.     restore(i_state);
  207. }
  208. void
  209. setstate(tcb,newstate)
  210. register struct tcb *tcb;
  211. register char newstate;
  212. {
  213.     register char oldstate;
  214.  
  215.     oldstate = tcb->state;
  216.     tcb->state = newstate;
  217.     if(tcb->s_upcall){
  218.         (*tcb->s_upcall)(tcb,oldstate,newstate);
  219.     }
  220.     /* Notify the user that he can begin sending data */
  221.     if(tcb->t_upcall && newstate == ESTABLISHED){
  222.         (*tcb->t_upcall)(tcb,tcb->window - tcb->sndcnt);
  223.     }
  224. }
  225. #ifdef    TRACE
  226. /* TCP connection states */
  227. char *tcpstates[] = {
  228.     "Closed",
  229.     "Listen",
  230.     "SYN sent",
  231.     "SYN received",
  232.     "Established",
  233.     "FIN wait 1",
  234.     "FIN wait 2",
  235.     "Close wait",
  236.     "Closing",
  237.     "Last ACK",
  238.     "Time wait"
  239. };
  240. /* TCP segment header flags */
  241. char *tcpflags[] = {
  242.     "FIN",    /* 0x01 */
  243.     "SYN",    /* 0x02 */
  244.     "RST",    /* 0x04 */
  245.     "PSH",    /* 0x08 */
  246.     "ACK",    /* 0x10 */
  247.     "URG"    /* 0x20 */
  248. };
  249.  
  250. /* TCP closing reasons */
  251. char *reasons[] = {
  252.     "Normal",
  253.     "Reset",
  254.     "Timeout",
  255.     "ICMP"
  256. };
  257. /* Return 1 if arg is a valid TCB, 0 otherwise */
  258. int
  259. tcpval(tcb)
  260. struct tcb *tcb;
  261. {
  262.     register int i;
  263.     register struct tcb *tcb1;
  264.  
  265.     for(i=0;i<NTCB;i++){
  266.         for(tcb1=tcbs[i];tcb1 != NULLTCB;tcb1 = tcb1->next){
  267.             if(tcb1 == tcb)
  268.                 return 1;
  269.         }
  270.     }
  271.     return 0;
  272. }
  273.  
  274. /* Dump TCP stats and summary of all TCBs
  275. /* &TCB Rcv-Q Snd-Q  Local socket           Remote socket          State
  276.  * 1234     0     0  xxx.xxx.xxx.xxx:xxxxx  xxx.xxx.xxx.xxx:xxxxx  Established
  277.  */
  278. int
  279. tcpstat()
  280. {
  281.     register int i;
  282.     register struct tcb *tcb;
  283.     char *psocket();
  284.  
  285.     printf("conout %u conin %u reset out %u runt %u chksum err %u bdcsts %u\r\n",
  286.         tcp_stat.conout,tcp_stat.conin,tcp_stat.resets,tcp_stat.runt,
  287.         tcp_stat.checksum,tcp_stat.bdcsts);
  288. #ifdef    AMIGA
  289.     printf("&TCB   Rcv-Q Snd-Q  Local socket           Remote socket          State\r\n");
  290. #else
  291.     printf("&TCB Rcv-Q Snd-Q  Local socket           Remote socket          State\r\n");
  292. #endif
  293.     for(i=0;i<NTCB;i++){
  294.         for(tcb=tcbs[i];tcb != NULLTCB;tcb = tcb->next){
  295. #ifdef    AMIGA
  296.             printf("%6lx%6u%6u  ",(unsigned long)tcb,
  297.                         tcb->rcvcnt,tcb->sndcnt);
  298. #else
  299.             printf("%4x%6u%6u  ",(int)tcb,tcb->rcvcnt,tcb->sndcnt);
  300. #endif
  301.             printf("%-23s",psocket(&tcb->conn.local));
  302.             printf("%-23s",psocket(&tcb->conn.remote));
  303.             printf("%-s\r\n",tcpstates[tcb->state]);
  304.         }
  305.     }
  306.     fflush(stdout);
  307.     return 0;
  308. }
  309. /* Dump a TCP control block */
  310. void
  311. state_tcp(tcb)
  312. struct tcb *tcb;
  313. {
  314.     int32 sent,recvd;
  315.  
  316.     if(tcb == NULLTCB)
  317.         return;
  318.     /* Compute total data sent and received; take out SYN and FIN */
  319.     sent = tcb->snd.una - tcb->iss;    /* Acknowledged data only */
  320.     recvd = tcb->rcv.nxt - tcb->irs;
  321.     switch(tcb->state){
  322.     case LISTEN:
  323.     case SYN_SENT:        /* Nothing received or acked yet */
  324.         sent = recvd = 0;    
  325.         break;
  326.     case SYN_RECEIVED:
  327.         recvd--;    /* Got SYN, no data acked yet */
  328.         sent = 0;
  329.         break;
  330.     case ESTABLISHED:    /* Got and sent SYN */
  331.     case FINWAIT1:        /* FIN not acked yet */
  332.         sent--;
  333.         recvd--;
  334.         break;
  335.     case FINWAIT2:        /* Our SYN and FIN both acked */
  336.         sent -= 2;
  337.         recvd--;
  338.         break;
  339.     case CLOSE_WAIT:    /* Got SYN and FIN, our FIN not yet acked */
  340.     case CLOSING:
  341.     case LAST_ACK:
  342.         sent--;
  343.         recvd -= 2;
  344.         break;
  345.     case TIME_WAIT:        /* Sent and received SYN/FIN, all acked */
  346.         sent -= 2;
  347.         recvd -= 2;
  348.         break;
  349.     }
  350.     printf("Local: %s",psocket(&tcb->conn.local));
  351.     printf(" Remote: %s",psocket(&tcb->conn.remote));
  352.     printf(" State: %s\r\n",tcpstates[tcb->state]);
  353.     printf("      Init seq    Unack     Next      WL1      WL2  Wind   MSS Queue      Total\r\n");
  354.     printf("Send:");
  355.     printf("%9lx",tcb->iss);
  356.     printf("%9lx",tcb->snd.una);
  357.     printf("%9lx",tcb->snd.nxt);
  358.     printf("%9lx",tcb->snd.wl1);
  359.     printf("%9lx",tcb->snd.wl2);
  360.     printf("%6u",tcb->snd.wnd);
  361.     printf("%6u",tcb->mss);
  362.     printf("%6u",tcb->sndcnt);
  363.     printf("%11lu\r\n",sent);
  364.  
  365.     printf("Recv:");
  366.     printf("%9lx",tcb->irs);
  367.     printf("         ");
  368.     printf("%9lx",tcb->rcv.nxt);
  369.     printf("         ");
  370.     printf("         ");
  371.     printf("%6u",tcb->rcv.wnd);
  372.     printf("      ");
  373.     printf("%6u",tcb->rcvcnt);
  374.     printf("%11lu\r\n",recvd);
  375.  
  376.     if(tcb->reseq != (struct reseq *)NULL){
  377.         register struct reseq *rp;
  378.  
  379.         printf("Reassembly queue:\r\n");
  380.         for(rp = tcb->reseq;rp != (struct reseq *)NULL; rp = rp->next){
  381.             printf("  seq x%lx %u bytes\r\n",rp->seg.seq,rp->length);
  382.         }
  383.     }
  384.     printf("Retry %u",tcb->retry);
  385.     switch(tcb->timer.state){
  386.     case TIMER_STOP:
  387.         printf(" Timer stopped");
  388.         break;
  389.     case TIMER_RUN:
  390.         printf(" Timer running (%ld/%ld mS)",
  391.          (long)MSPTICK * (tcb->timer.start - tcb->timer.count),
  392.          (long)MSPTICK * tcb->timer.start);
  393.         break;
  394.     case TIMER_EXPIRE:
  395.         printf(" Timer expired");
  396.     }
  397.     printf(" Smoothed round trip time %ld mS\r\n",tcb->srtt);
  398.     fflush(stdout);
  399. }
  400.  
  401. /* Dump a TCP segment header. Assumed to be in network byte order */
  402. void
  403. tcp_dump(bp,source,dest,check)
  404. struct mbuf *bp;
  405. int32 source,dest;    /* IP source and dest addresses */
  406. int check;        /* 0 if checksum test is to be bypassed */
  407. {
  408.     int hdr_len,i;
  409.     register struct tcp_header *tcph;
  410.     struct pseudo_header ph;
  411.     char tmpbuf;
  412.  
  413.     if(bp == NULLBUF)
  414.         return;
  415.     /* If packet isn't in a single buffer, make a temporary copy and
  416.      * note the fact so we free it later
  417.      */
  418.     if(bp->next != NULLBUF){
  419.         bp = copy_p(bp,len_mbuf(bp));
  420.         tmpbuf = 1;
  421.     } else
  422.         tmpbuf = 0;
  423.         
  424.     tcph = (struct tcp_header *)bp->data;
  425.     hdr_len = hinibble(tcph->offset) * sizeof(int32);
  426.     printf("TCP: %u->%u Seq x%lx",
  427.         ntohs(tcph->source),ntohs(tcph->dest),
  428.         ntohl(tcph->seq),ntohl(tcph->ack));
  429.     
  430.     if(tcph->flags & ACK)
  431.         printf(" Ack x%lx",ntohl(tcph->ack));
  432.     for(i=0;i<6;i++){
  433.         if(tcph->flags & 1 << i){
  434.             printf(" %s",tcpflags[i]);
  435.         }
  436.     }
  437.     printf(" Wnd %u",ntohs(tcph->wnd));
  438.     if(tcph->flags & URG)
  439.         printf(" UP x%x",ntohs(tcph->up));
  440.  
  441.     if(hdr_len > sizeof(struct tcp_header)){
  442.         struct mss *mssp;
  443.     
  444.         mssp = (struct mss *)(tcph + 1);
  445.         if(mssp->kind == MSS_KIND && mssp->length == MSS_LENGTH){
  446.             printf(" MSS %u",ntohs(mssp->mss));
  447.         }
  448.     }
  449.     /* Verify checksum */
  450.     if(check){
  451.         ph.source = source;
  452.         ph.dest = dest;
  453.         ph.protocol = TCP_PTCL;
  454.         ph.length = len_mbuf(bp);
  455.         ph.zero = 0;
  456.         if((i = cksum(&ph,bp,ph.length)) != 0)
  457.             printf(" CHECKSUM ERROR (%u)",i);
  458.     }
  459.     printf("\r\n");
  460.     if(tmpbuf)
  461.         free_p(bp);
  462. }
  463. #endif
  464.